﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NDF.XnaLibrary.EnumEqualityComparers;

namespace NDF.XnaLibrary.Models
{
	/// <summary>
	/// A class that keeps track of all added and removed items in the inventory of a character.
	/// </summary>
	public class Inventory
	{
		//An array to hold all the values from the EquipmentSlot enum for easy and clean initialization
		private static readonly Array EquipmentSlotsValues = System.Enum.GetValues(typeof(EquipmentSlot));

		private Dictionary<EquipmentSlot, Equipment> mInventory;
		private List<Equipment> mItems;

		#region Events
		public delegate void InventoryEventHandler(object sender, InventoryEventArgs e);

		/// <summary>
		/// Event that is raised every time an item is added.
		/// </summary>
		public event InventoryEventHandler ItemEquipped;

		/// <summary>
		/// Event that is raised every time an item has been removed.
		/// </summary>
		public event InventoryEventHandler ItemRemoved;

		private void OnItemEquipped(InventoryEventArgs eventArgs)
		{
			if (ItemEquipped != null)
				ItemEquipped(this, eventArgs);
		}

		private void OnItemRemoved(InventoryEventArgs eventArgs)
		{
			if (ItemRemoved != null)
				ItemRemoved(this, eventArgs);
		}

		#endregion

		#region Constructors

		/// <summary>
		/// Initializes a new empty instance of the Inventory class.
		/// </summary>
		public Inventory()
		{			
			mInventory =
				new Dictionary<EquipmentSlot, Equipment>(EquipmentSlotsValues.Length, EquipmentSlotEqualityComparer.Default);
			mItems = new List<Equipment>(EquipmentSlotsValues.Length);

			foreach (EquipmentSlot slot in EquipmentSlotsValues)
			{
				mInventory.Add(slot, null);
			}
		}

		#endregion

		#region Properties

		/// <summary>
		/// Gets all of the currently equipped items. The order of the items is unspecified.
		/// </summary>
		public List<Equipment> Items
		{
			get { return mItems; }
		}

		#endregion

		#region Methods

		/// <summary>
		/// Gets the item at the specified slot.
		/// </summary>
		/// <param name="slot">The slot to get the item from.</param>
		/// <returns>The item at the specified slot or null if there`s no item.</returns>
		public Equipment GetItem(EquipmentSlot slot)
		{
			return mInventory[slot];
		}

		/// <summary>
		/// Equips the specified item at the specified slot.
		/// </summary>
		/// <param name="slot">The slot to equip the item to.</param>
		/// <param name="item">The item to be equipped.</param>
		public void EquipItem(EquipmentSlot slot, Equipment item)
		{
			if (item == null)
				throw new ArgumentNullException("item", "item cant be null!");

			item.Slot = slot;
			mInventory[slot] = item;
			mItems.Add(item);
			OnItemEquipped(new InventoryEventArgs(slot, item));
		}

		/// <summary>
		/// Removes the item at the specified slot.
		/// </summary>
		/// <param name="slot">The slot to removed the item from.</param>
		public void RemoveItem(EquipmentSlot slot)
		{
			Equipment item = mInventory[slot];
			item.Slot = EquipmentSlot.None;
			mItems.Remove(item);
			mInventory[slot] = null;
			OnItemRemoved(new InventoryEventArgs(slot, item));
		}

		#endregion
	}

	/// <summary>
	/// Provides data for the NDF.Xna.Library.Inventory class` events.
	/// </summary>
	public class InventoryEventArgs
	{
		/// <summary>
		/// Gets the slot for the item that triggered the event.
		/// </summary>
		public EquipmentSlot Slot { get; private set; }

		/// <summary>
		/// Gets the item that triggered the event.
		/// </summary>
		public Equipment Item { get; private set; }

		public InventoryEventArgs(EquipmentSlot slot, Equipment item)
		{
			Slot = slot;
			Item = item;
		}
	}
}
